/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uk.ac.liv.datacompression;

import java.io.*;
import javax.xml.parsers.*;
import com.sun.xml.fastinfoset.sax.*;
import javax.xml.stream.*;
import javax.xml.bind.*;
import javax.xml.stream.*;
import com.sun.xml.fastinfoset.stax.*;

import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import org.jvnet.fastinfoset.*;

import java.io.*;
import javax.xml.bind.*;
import javax.xml.stream.*;
import com.sun.xml.fastinfoset.stax.*;

import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

//import ncsa.hdf.hdf5lib.H5;
//import ncsa.hdf.hdf5lib.HDF5Constants;


/**
 *
 * @author jonesar
 */
public class DataCompressionTest {
    
   private String inputXML = "resources/SA_silac_a24.mzid";
   // private String inputXML = "resources/219.mzML";
    //private String elementName = "spectrum";
   private String elementName = "Peptide";
    
    
    //private String inputGZMzid = "C:/Work/PSI/mzIdentML/FastInfosets/FastInfoTest/resources/SA_silac_a24.mzid.gz";
    //private String outputGZMzid = "C:/Work/PSI/mzIdentML/FastInfosets/FastInfoTest/resources/SA_silac_a24_Test.mzid";
    private String outputFI = "resources/test.fi";
    private String outputFIGzipped = "resources/test.fi.gz";
    private String outputXML = "resources/test_copy.xml";
    

    
    public static void main( String[] args )
    {
        long time1=0;
        long time2=0;
        long execTime=0;
        

        
        DataCompressionTest dataCompress = new DataCompressionTest ();
        
        
        System.out.println("Creating FI file from XML " + dataCompress.inputXML + " size:" + new File(dataCompress.inputXML).length() + " "); 
        time1 = System.currentTimeMillis();
        dataCompress.createFIFile(dataCompress.inputXML, dataCompress.outputFI);
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Done in " + execTime + " FI output size: " + new File(dataCompress.outputFI).length() + " ");
        
        System.out.print("Zipping FI file...");
        time1 = System.currentTimeMillis();
        dataCompress.Gzip(dataCompress.outputFI,dataCompress.outputFIGzipped);
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Done in " + execTime + " output size: " + new File(dataCompress.outputFIGzipped).length() + " "); 
        
        System.out.print("Zipping XML file...");
        time1 = System.currentTimeMillis();
        dataCompress.Gzip(dataCompress.inputXML,dataCompress.inputXML+".gz");
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Done in " + execTime+ " output size: " + new File(dataCompress.inputXML+".gz").length() + " "); 

        
        System.out.print("Unzipping FI file...");
        time1 = System.currentTimeMillis();
        dataCompress.Gunzip(dataCompress.outputFIGzipped,dataCompress.outputFI);
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Done in " + execTime);
        
        
        System.out.print("Unzipping XML file...");
        time1 = System.currentTimeMillis();
        dataCompress.Gunzip(dataCompress.inputXML+".gz",dataCompress.outputXML);
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Time to gunzip XML:" + execTime);
        
        System.out.print("Parsing XML file...");
        time1 = System.currentTimeMillis();
        int elementCount = dataCompress.countElementsFromXML(dataCompress.outputXML,dataCompress.elementName);
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Time to count elements from XML:" + execTime + " count: " + elementCount);
        
        System.out.print("Parsing FI file...");
        time1 = System.currentTimeMillis();
        elementCount = dataCompress.countElementsFromFI(dataCompress.outputFI,dataCompress.elementName);
        time2 = System.currentTimeMillis();
        execTime = time2-time1;
        System.out.println("Time to count elements from FI:" + execTime + " count: " + elementCount);
        
        
        /*
         * Some notes:
         * 
         * Gunzip is not really a particularly slow step - gunzip to create a 140MB file takes 0.7seconds on a current desktop. 
         * These simple tests seem to suggest that reading from FI is somewhat quicker than reading from XML - perhaps twice as fast in some cases
         * There is nothing to stop using gzip in tandem with FI
         * 
         * 
Example results:
Input file
* Creating FI file from XML resources/SA_silac_a24.mzid size:147992378 Done in 2549 output size: 61889950 
Zipping FI file...Done in 2126 output size: 17001819 
Zipping XML file...Done in 2754 output size: 17822126 
Unzipping FI file...Done in 532
Unzipping XML file...Time to gunzip XML:829
Parsing XML file...Time to count elements from XML:1283 count: 52936
Parsing FI file...Time to count elements from FI:654 count: 52936
* 
* 
Creating FI file from XML C:/Work/PSI/mzIdentML/FastInfosets/FastInfoTest/resources/SA_silac_a24.mzid size:147992378 Done in 2723 output size: 61889950 
Zipping FI file...Done in 2238 output size: 17001819 
Zipping XML file...Done in 2798 output size: 17822126 
Unzipping FI file...Done in 520
Unzipping XML file...Time to gunzip XML:1018
Parsing XML file...Time to count elements from XML:1385 count: 52936
Parsing FI file...Time to count elements from FI:642 count: 52936
* 
* 
* 
* 
* 
Creating FI file from XML C:/Work/PSI/mzIdentML/FastInfosets/FastInfoTest/resources/219.mzML size:1775102239 Done in 11908 output size: 1662819144 
Zipping FI file...Done in 86402 output size: 1247799395 
Zipping XML file...Done in 85206 output size: 1250495618 
Unzipping FI file...Done in 22705
Unzipping XML file...Time to gunzip XML:31231
Parsing XML file...Time to count elements from XML:6452 count: 28634
Parsing FI file...Time to count elements from FI:5299 count: 28634
* 
* 
* Creating FI file from XML resources/219.mzML size:1775102241 Done in 118284 output size: 1662819146 
Zipping FI file...Done in 85012 output size: 1247799274 
Zipping XML file...Done in 84455 output size: 1250495754 
Unzipping FI file...Done in 23220
Unzipping XML file...Time to gunzip XML:23423
Parsing XML file...Time to count elements from XML:4925 count: 28634
Parsing FI file...Time to count elements from FI:5780 count: 28634
* 
* 
* 

* 
* 
* 
* 
* 
         * 
         * 
         */
        
        
        //dataCompress.outputCopy();
    }
    
    private void createFIFile(String xmlFile,String fiFile){
        
        try{
            // Get the input stream for the XML document
            InputStream xmlDocument = new FileInputStream(xmlFile);
            // Set up output stream for fast infoset document
            OutputStream fiDocument = new FileOutputStream(fiFile);

            // Create Fast Infoset SAX serializer
            SAXDocumentSerializer saxDocumentSerializer = new SAXDocumentSerializer();
            // Set the output stream
            saxDocumentSerializer.setOutputStream(fiDocument);

            // Instantiate JAXP SAX parser factory
            SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
            /* Set parser to be namespace aware
            * Very important to do otherwise invalid FI documents will be
            * created by the SAXDocumentSerializer
            */
            saxParserFactory.setNamespaceAware(true);
            // Instantiate the JAXP SAX parser
            SAXParser saxParser = saxParserFactory.newSAXParser();
            // Set the lexical handler
            saxParser.setProperty("http://xml.org/sax/properties/lexical-handler", saxDocumentSerializer);
            // Parse the XML document and convert to a fast infoset document
            saxParser.parse(xmlDocument, saxDocumentSerializer);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    
    private void saveFIAsXML(String fiFile, String xmlFile){

        try{
            // Get the input stream for the fast infoset document
            InputStream fiDocument =  new FileInputStream(fiFile);
            
            
            
            // Create the transformer
            Transformer tx = TransformerFactory.newInstance().newTransformer();
            // Transform to convert the FI document to an XML document
            tx.transform(new FastInfosetSource(fiDocument), new StreamResult(xmlFile));
            
            //XMLStreamReader streamReader = new StAXDocumentParser(fiDocument);
            
            //mzIdentMLUnmarshaller = new MzIdentMLUnmarshaller(fiDocument);
            //mzIdentML = (MzIdentML) mzIdentMLUnmarshaller.unmarshal(MzIdentML.class);
        } 
        catch (Exception e) {
                e.printStackTrace();
        }
    }
    
    private void Gunzip(String gzippedFile, String newFile){
        
        try{
            GZIPInputStream gin = new GZIPInputStream(new FileInputStream(gzippedFile));
            File outFile = new File(newFile);
            FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buf = new byte[100000];
            int len;
            while ((len = gin.read(buf)) > 0) {
                fos.write(buf, 0, len);
            }
            fos.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    
        private void Gzip(String startingFile, String gzippedFile){
        
        try{
            GZIPOutputStream gout = new GZIPOutputStream(new FileOutputStream(gzippedFile));
            File inFile = new File(startingFile);
            FileInputStream fis = new FileInputStream(inFile);
            byte[] buf = new byte[100000];
            int len;
            while ((len = fis.read(buf)) > 0) {
                gout.write(buf, 0, len);
            }
            gout.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    
    
    private int countElementsFromXML(String xmlFile, String elementName){
        // Get the input stream for the fast infoset document
        int elementCounter = 0;
        try{
            //InputStream fiDocument =  new FileInputStream(outputGZMzid);

            // Create the StAX XMLStreamReader using the input stream
            //XMLStreamReader streamReader = new StAXDocumentParser(fiDocument);
            XMLInputFactory factory = XMLInputFactory.newInstance();
            XMLStreamReader streamReader = factory.createXMLStreamReader(new FileReader(xmlFile));
            
            while(streamReader.hasNext()){
                streamReader.next();
                if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT){
                    if(streamReader.getLocalName().equals(elementName)){
                        elementCounter++;                        
                    }
                    
                }
            }
            //System.out.println("Pep counter:" + pepCounter);
        }
        catch(Exception e){
             e.printStackTrace();
        }
        return elementCounter;
    }
    
    
    private int countElementsFromFI(String fiFile, String elementName){
        // Get the input stream for the fast infoset document
        int elementCounter = 0;
        try{
            InputStream fiDocument =  new FileInputStream(fiFile);

            // Create the StAX XMLStreamReader using the input stream
            XMLStreamReader streamReader = new StAXDocumentParser(fiDocument);

            while(streamReader.hasNext()){
                streamReader.next();
                if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT){
                    if(streamReader.getLocalName().equals(elementName)){
                        elementCounter++;                        
                    }
                    
                }
            }
            //System.out.println("Pep counter:" + pepCounter);
        }
        catch(Exception e){
             e.printStackTrace();
        }
        return elementCounter;
    }
}
